iT邦幫忙

2024 iThome 鐵人賽

DAY 3
0
JavaScript

Signal API in Angular系列 第 3

Day 03 - Angular 的 Signal API

  • 分享至 

  • xImage
  •  

Angular 16 中最重要的API就是 Signal API。一個Signal可以持有原始值或物件,當值更新時會通知模板和相依的 Signals。
不同於有數百個RxJS operators,Signal API非常簡單,只有少數幾個方法。

初始化一個新的 Signal

count = signal(5);  // a number Signal
hello = signal('Hello');  // a string Signal

結果是一個型態為 WritableSignal 的實例。

修改一個既有的 Signal

API 中有兩個方法可以修改既有的Signal:set()update()set方法會覆寫 Signal 的目前值,而update方法會執行一個回呼函數 (callback),根據目前值來產生新的值。

this.count.set(10);  // 將 count Signal 設定為 10
this.hello.update((prev) => `${prev} World.`);  // 將 hello Signal 更新為 Hello World

建立一個唯讀的 Signal

WritableSignal有個asReadonly方法可以建立一個唯讀的 Signal。唯讀的Signal沒有setupdate方法,呼叫這些方法時編譯器會發出錯誤訊息。

countRead = this.count.asReadonly();  // 建立一個唯讀的 Signal
countRead.set(1000);  // 會產生錯誤

從 Signal 衍生出新的 Signal

computed函數可以從既有的Signal衍生出一個唯讀的 Signal。同樣地,它也沒有修改值的方法。當它相依的任何`Signal更新時,回呼函數會重新執行以計算新的值。

double = computed(() => count() * 2);
triple = computed(() => count() * 3);

例如,當count Signal從5更新為10時,doubletriple的新值分別是2030
在範本中顯示Signal值

<div>
  <p>name: {{ name() }}</p>
  <p>count: {{ count() }}</p>
</div>

要在HTML範本中顯示Signal值,可以將它們作為函數呼叫插入double curly braces。當namecount signals更新時,組件會被標記為髒,下一次變更偵測時,範本會重新渲染以顯示新值。

Effects

Effects在應用程式需要關注Signal變更時很有用。Effect必須在有效的injection context中執行,例如constructor或欄位初始化 (Field initializers)。

// 在建構函數中
constructor() {
  effect(() => console.log('Effect in constructor', this.count(), this.hello()));
}
// 在欄位初始化中
#logEffect = effect(() => console.log('Effect in field initialization', this.count(), this.hello()));

範例中的console.log會在counthello變更時執行。

完整範例

import { Component, computed, effect, signal } from '@angular/core';

@Component({
 selector: 'app-root',
 standalone: true,
 template: `
   <h1>Hello from {{ name }}!</h1>
   <p>Count: {{ count() }}</p>
   <p>Hello: {{ hello() }}</p>
   <p>Double: {{ double() }}</p>
   <p>Triple: {{ triple() }}</p>

   <button (click)="update()">Click me to update signal</button>   
   <button (click)="count.set(5); hello.set('Hello')">Reset</button>   
 `,
})
export class App {
 name = 'IT Home Ironman 2024 day 3';

 count = signal(5);
 hello = signal('Hello');
 countRead = this.count.asReadonly();

 double = computed(() => this.count() * 2);
 triple = computed(() => this.count() * 3);

 // in field initialization
 #logEffect = effect(() => console.log('Effect in field initialization', this.count(), this.hello()));

 constructor() {
   effect(() => {
     console.log('Effect in constructor', this.count(), this.hello());
   })
 }

 update() {
   this.count.set(10);
   this.hello.update((prev) => `${prev} World.`);

   // compiler error
   // this.countRead.set(200);

   // compiler error
   // this.double.set(200);
 }
}

結論:

  • 介紹 Signal API 以及為什麼它對 Angular 框架如此重要
  • 描述 Signal API 中的方法並展示範例

這是我2024鐵人賽第3天的心得分享。

參考:

  • Angular官方Signal文件:https://angular-dev-site.web.app/guide/signals
  • Stackblitz 示範:https://stackblitz.com/edit/stackblitz-starters-frbgt5?file=src%2Fmain.ts

上一篇
Day 02 - 使用基本構建塊建立 Angular 應用程式
下一篇
Day 04 - Signal的技巧與陷阱
系列文
Signal API in Angular10
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言